﻿using System;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Configuration;
using Db4objects.Db4o;
using Db4objects.Db4o.Query;
using System.Linq;
using System.Linq.Expressions;
using Domain;
using Db4objects.Db4o.CS;

namespace DAO
{
    
    public static class Connect
    {
        private enum enum_connType { 
            server = 0,
            local = 1
        }

        static IObjectContainer rootContainer;
        static enum_connType connType = enum_connType.local;

        private static string connStringLocal()
        {
            return ConfigurationSettings.AppSettings["hc_db4o_connstr"];
        }

        private static string connStringServer()
        {
            //return ConfigurationManager.AppSettings["cs"];
            return ConfigurationSettings.AppSettings["hc_db4o_connstr"];
        }

        public static IObjectContainer getDataBase() {
            
            if(rootContainer==null)
                if(connType == enum_connType.local)
                    rootContainer = Db4oFactory.OpenFile(Connect.connStringLocal());
                else
                {
                    IObjectServer server = Db4oClientServer.OpenServer(Db4oClientServer.NewServerConfiguration(), Connect.connStringServer(), 0);
                    rootContainer = server.OpenClient();
                }

            return rootContainer.Ext().OpenSession();
        }
        

        public static object getMax(IObjectContainer db, object idOb, string idfield, Hashtable constrains)
        {
            IQuery q = db.Query();
            q.Constrain(idOb.GetType());
            foreach (object key in constrains.Keys)
                q.Descend(getBackingField(key.ToString())).Constrain(constrains[key]);

            q.Descend(getBackingField(idfield)).OrderDescending();
            IObjectSet result = q.Execute();
            while (result.HasNext())
            {
                return (object)result.Next();

            }
            return null;
            
        }

        private static string getBackingField(string field)
        {
            return "<" + field + ">k__BackingField";
        }

        public static List<Object> resultToList(IObjectSet os) {
            List<Object> lstO = new List<Object>();
            while (os.HasNext())
            {
                lstO.Add(os.Next());
            }
            return lstO;
        }

        public static string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
        {
            return (propertyExpression.Body as MemberExpression).Member.Name;
        }

        public static void assignId(IObjectContainer db, object o)
        {
            if (typeof(string).IsInstanceOfType(o)) //workaround 4 string[]
            {
                return;
            }

            if (typeof(DomainObject).IsInstanceOfType(o))
            {
                DomainObject c = (DomainObject)o;
                c.db4oid = db.Ext().GetID(c);
            }

            foreach (System.Reflection.PropertyInfo ao in o.GetType().GetProperties())
            {
                if (typeof(DomainObject).IsInstanceOfType(ao.GetValue(o, null)))
                {
                    assignId(db, ao.GetValue(o, null)); 
                }
                else if (ao.PropertyType.IsClass && ao.GetValue(o, null) != null)
                {
                    lstAssignId(db, ((IEnumerable)ao.GetValue(o, null)).OfType<object>().ToList());
                }

            }

        }

        public static void lstAssignId(IObjectContainer db, List<object> lo)
        {
            foreach (object o in lo)
                assignId(db, o);
        }


        public static void rebindId(IObjectContainer db, object o)
        {
            if (typeof(string).IsInstanceOfType(o)) //workaround 4 string[]
            {
                return;
            }

            if (typeof(DomainObject).IsInstanceOfType(o))
            {
                DomainObject c = (DomainObject)o;
                if(c.db4oid.HasValue)
                    db.Ext().Bind(c, c.db4oid.Value);
            }

            foreach (System.Reflection.PropertyInfo ao in o.GetType().GetProperties())
            {
                if (typeof(DomainObject).IsInstanceOfType(ao.GetValue(o, null)))
                {
                    rebindId(db, ao.GetValue(o, null));
                }
                else if (ao.PropertyType.IsClass && ao.GetValue(o, null) != null)
                {
                    lstRebindId(db, ((IEnumerable)ao.GetValue(o, null)).OfType<object>().ToList());
                }

            }

        }

        public static void lstRebindId(IObjectContainer db, List<object> lo)
        {
            foreach (object o in lo)
                rebindId(db, o);
        }

    }
     
}
